package admin

import (
	j_log "config-client-v1/init/j-log"
	"config-client-v1/model"
	"config-client-v1/utils/tools"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"gorm.io/gorm"
	"strings"
	"time"
)

func (con FSController) GenModuleNames(ctx *gin.Context) {
	param := struct {
		FSID       int    `json:"fs_id" binding:"required"`       // 自研设备ID
		ModuleType string `json:"module_type" binding:"required"` // 模块类型就等于code2 , 00-14
		ModuleNum  int    `json:"module_num" binding:"required"`  // 模块数量
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	code2, ok := model.AllowFSCode2[param.ModuleType]
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数 module_type",
			"data":    "",
		})
		return
	}
	fse := &model.FSEquip{}
	exist, err := fse.Exists(param.FSID)
	if !exist {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数 fs_id",
			"data":    err,
		})
		return
	}
	code1 := fse.Code1
	usedCode3 := make([]string, 0)
	err = model.DB.Model(&model.FSModule{}).Where("fs_id = ? AND code2 = ?", param.FSID, code2).Pluck("code3", &usedCode3).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	availableCode3 := model.GetAvailableCode(model.AllCode3FS(), usedCode3)
	if len(availableCode3) < param.ModuleNum {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "可用的模块序号不足, code3不足",
			"data": map[string]interface{}{
				"code": code1 + "-" + code2,
			},
		})
	}
	code3Arr := availableCode3[0:param.ModuleNum] // 准备新增的 code3
	names := make([]string, 0)
	for _, code3 := range code3Arr {
		names = append(names, param.ModuleType+code3)
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"module_names": names,
		},
	})
}
func (con FSController) ModuleTypeList(ctx *gin.Context) {
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	list := make([]*model.FSModule, 0)
	err = model.DB.Preload("FrameItem", func(tx *gorm.DB) *gorm.DB {
		return tx.Select("id", "module_id", "addr")
	}).Where("fs_id = ?", param.FSID).
		Order("id ASC").
		Select("id", "fs_id", "module_type").
		Offset(0).Limit(5000).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	typeList := make([]*model.ModuleType, 0)
	typeList = append(typeList, &model.ModuleType{ModuleType: "AI", FSID: param.FSID})
	typeList = append(typeList, &model.ModuleType{ModuleType: "AQ", FSID: param.FSID})
	typeList = append(typeList, &model.ModuleType{ModuleType: "DI", FSID: param.FSID})
	typeList = append(typeList, &model.ModuleType{ModuleType: "DQ", FSID: param.FSID})
	typeList = append(typeList, &model.ModuleType{ModuleType: "Other", FSID: param.FSID})

	for _, row1 := range typeList {
		moduleNum := 0
		channelNum := 0
		for _, module := range list {
			if row1.ModuleType == module.ModuleType {
				moduleNum++
				channelNum += len(module.FrameItem)
			}
		}
		row1.ModuleNum = moduleNum
		row1.ChannelNum = channelNum
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list": typeList,
		},
	})
}
func (con FSController) ModuleList(ctx *gin.Context) {
	param := struct {
		FSID       int    `json:"fs_id" binding:"required"`
		ModuleType string `json:"module_type"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	if param.ModuleType != "" {
		_, ok := model.AllowFSCode2[param.ModuleType]
		if !ok {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "无效的参数 module_type",
				"data":    "",
			})
			return
		}
	}

	tx := model.DB.Model(&model.FSModule{}).Where("code2 in ?", []string{"00", "01", "02", "03", "04"})
	if param.ModuleType != "" {
		tx.Where("module_type = ?", param.ModuleType)
	}

	list := make([]*model.FSModule, 0)
	err = tx.Preload("FrameItem").Where("fs_id = ?", param.FSID).
		Order("module_type ASC,code3 ASC").
		Select("id", "fs_id", "code3", "module_type", "module_name", "create_time", "update_time").
		Offset(0).Limit(5000).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	moduleList := make([]*model.ModuleList, 0)

	for _, module := range list {
		tmp := &model.ModuleList{
			ID:         module.ID,
			ModuleType: module.ModuleType,
			Code3:      module.Code3,
			ChannelNum: len(module.FrameItem),
			FSID:       module.FSID,
			ModuleName: module.ModuleName,
			List:       module.FrameItem,
			CreateTime: module.CreateTime,
			UpdateTime: module.UpdateTime,
		}
		tmp.ChannelNum = len(module.FrameItem)
		moduleList = append(moduleList, tmp)
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list": moduleList,
		},
	})
}

// ModuleAdd 新增时指定类型AI,AQ为 DI,DQ为 bool
func (con FSController) ModuleAdd(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		FSID        int    `json:"fs_id" binding:"required"`         // 自研设备ID
		ModuleType  string `json:"module_type" binding:"required"`   // 模块类型就等于code2 , AI-Other
		ChannelNum  int    `json:"channel_num" binding:"required"`   // 通道数量(变量数量)
		ModuleNum   int    `json:"module_num" binding:"required"`    // 模块数量
		ModuleNames string `json:"module_names"  binding:"required"` // 模块名称，多个用逗号分隔
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	code2, ok := model.AllowModuleCode2[param.ModuleType]
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数 module_type",
			"data":    "",
		})
		return
	}
	_, ok = model.AllowChannelValue[param.ChannelNum]
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数 channel_num",
			"data":    "通道数量可选范围 [8,16,32]",
		})
		return
	}
	names := strings.Split(param.ModuleNames, ",")
	if len(names) != param.ModuleNum {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "模块名称和模块数量不匹配",
			"data":    "",
		})
		return
	}
	if tools.HasDuplicatesStr(names) {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "模块名称不能重复",
			"data":    "",
		})
		return
	}
	fse := &model.FSEquip{}
	exist, err := fse.Exists(param.FSID)
	if !exist {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数 fs_id",
			"data":    err,
		})
		return
	}
	code1 := fse.Code1
	// 根据 code1_code2 选出可用的code3
	usedCode3 := make([]string, 0)
	err = model.DB.Model(&model.FSModule{}).Where("fs_id = ? AND code2 = ?", param.FSID, code2).Pluck("code3", &usedCode3).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	availableCode3 := model.GetAvailableCode(model.AllCode3FS(), usedCode3)
	if len(availableCode3) < param.ModuleNum {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "可用的模块序号不足, code3不足",
			"data": map[string]interface{}{
				"code": code1 + "-" + code2,
			},
		})
	}
	now := tools.GetNow()
	code3Arr := availableCode3[0:param.ModuleNum] // 准备新增的 code3
	// 新增 fs_module 模块
	modulesList := make([]*model.FSModule, 0)
	for index, code3 := range code3Arr {
		tmp := &model.FSModule{
			ProjectID:  userToken.ProjectID,
			FSID:       param.FSID,
			ModuleType: param.ModuleType,
			ModuleName: names[index],
			Code1:      code1,
			Code2:      code2,
			Code3:      code3,
			CreateTime: &now,
			UpdateTime: &now,
		}
		modulesList = append(modulesList, tmp)
	}
	// 验证变量地址是否够用
	err = model.DB.Transaction(func(tx *gorm.DB) error {
		/*--- 创建fs_module ---*/
		err = tx.Omit("FrameItem").Create(&modulesList).Error
		if err != nil {
			return err
		}
		/*--- 创建变量地址,自动生成变量地址 ---*/
		for _, module := range modulesList {
			availableCode4 := model.AllCode4FS()
			code4Arr := availableCode4[0:param.ChannelNum]
			list := make([]*model.FrameItem, 0)
			for _, code4 := range code4Arr {
				addr := code1 + "-" + code2 + "-" + module.Code3 + "-" + code4
				channelType := param.ModuleType
				if param.ModuleType == "Other" {
					channelType = "AI" // 真类型
				}

				specType := ""
				upper2LimitVarAddr := ""
				upperLimitVarAddr := ""
				lowerLimitVarAddr := ""
				lower2LimitVarAddr := ""
				upper2LimitEnable := uint8(0)
				upperLimitEnable := uint8(0)
				lowerLimitEnable := uint8(0)
				lower2LimitEnable := uint8(0)
				switch channelType {
				case "AI":
					fallthrough
				case "AQ":
					specType = "float32"
					upper2LimitVarAddr = addr + ".upper2"
					upperLimitVarAddr = addr + ".upper"
					lowerLimitVarAddr = addr + ".lower"
					lower2LimitVarAddr = addr + ".lower2"
					upper2LimitEnable = uint8(1)
					upperLimitEnable = uint8(1)
					lowerLimitEnable = uint8(1)
					lower2LimitEnable = uint8(1)
				case "DI":
					fallthrough
				case "DQ":
					specType = "uint8"
				}

				tmp := &model.FrameItem{
					ProjectID:          userToken.ProjectID,
					Code1:              code1,
					Code2:              code2,
					Code3:              module.Code3,
					Code4:              code4,
					FSID:               param.FSID,
					ModuleID:           module.ID,
					Endian:             "big",
					Addr:               addr,
					AlertVarAddr:       addr + ".alert",
					ShieldVarAddr:      addr + ".shield",
					Upper2LimitEnable:  upper2LimitEnable,
					Upper2LimitVarAddr: upper2LimitVarAddr,
					UpperLimitEnable:   upperLimitEnable,
					UpperLimitVarAddr:  upperLimitVarAddr,
					LowerLimitEnable:   lowerLimitEnable,
					LowerLimitVarAddr:  lowerLimitVarAddr,
					Lower2LimitEnable:  lower2LimitEnable,
					Lower2LimitVarAddr: lower2LimitVarAddr,
					FieldName:          "变量名 " + addr,
					ChannelType:        channelType,
					SpecType:           specType,
					RatioOperator:      "*",
					Ratio:              1,
				}
				list = append(list, tmp)
			}
			err = tx.Create(&list).Error
			if err != nil {
				return err
			}
			extendList := make([]*model.FrameItem, 0)
			for _, row := range list {
				row.AlertVarAddr = ""
				row.ShieldVarAddr = ""

				row.Upper2LimitEnable = 0
				row.Upper2LimitVarAddr = ""
				row.Upper2LimitValue = 0

				row.UpperLimitVarAddr = ""
				row.UpperLimitEnable = 0
				row.UpperLimitValue = 0

				row.LowerLimitEnable = 0
				row.LowerLimitVarAddr = ""
				row.LowerLimitValue = 0

				row.Lower2LimitEnable = 0
				row.Lower2LimitVarAddr = ""
				row.Lower2LimitValue = 0

				if row.ChannelType == "AI" || row.ChannelType == "AQ" {
					// 1. 上上限
					tmpUpper2 := *row
					tmpUpper2.PID = row.ID
					tmpUpper2.ID = 0
					tmpUpper2.IsInternal = 1
					tmpUpper2.SpecType = "float32"
					tmpUpper2.Addr = row.Addr + ".upper2"
					tmpUpper2.FieldName = row.Addr + ".上上限"
					tmpUpper2.Value = row.Upper2LimitValue
					extendList = append(extendList, &tmpUpper2)
					// 2. 上限
					tmpUpper := *row
					tmpUpper.PID = row.ID
					tmpUpper.ID = 0
					tmpUpper.IsInternal = 1
					tmpUpper.SpecType = "float32"
					tmpUpper.Addr = row.Addr + ".upper"
					tmpUpper.FieldName = row.Addr + ".上限"
					tmpUpper.Value = row.UpperLimitValue
					extendList = append(extendList, &tmpUpper)
					// 3. 下限
					tmpLower := *row
					tmpLower.PID = row.ID
					tmpLower.ID = 0
					tmpLower.IsInternal = 1
					tmpLower.SpecType = "float32"
					tmpLower.Addr = row.Addr + ".lower"
					tmpLower.FieldName = row.Addr + ".下限"
					tmpLower.Value = row.LowerLimitValue
					extendList = append(extendList, &tmpLower)
					// 4. 下下限
					tmpLower2 := *row
					tmpLower2.PID = row.ID
					tmpLower2.ID = 0
					tmpLower2.IsInternal = 1
					tmpLower2.SpecType = "float32"
					tmpLower2.Addr = row.Addr + ".lower2"
					tmpLower2.FieldName = row.Addr + ".下下限"
					tmpLower2.Value = row.Lower2LimitValue
					extendList = append(extendList, &tmpLower2)
				}
				// 1. 报警
				tmpAlert := *row
				tmpAlert.PID = row.ID
				tmpAlert.ID = 0
				tmpAlert.IsInternal = 1
				tmpAlert.SpecType = "uint8"
				tmpAlert.Addr = row.Addr + ".alert"
				tmpAlert.FieldName = row.Addr + ".报警"
				tmpAlert.Value = float64(row.AlertBit)
				extendList = append(extendList, &tmpAlert)
				// 2. 屏蔽
				tmpShield := *row
				tmpShield.PID = row.ID
				tmpShield.ID = 0
				tmpShield.IsInternal = 1
				tmpShield.SpecType = "uint8"
				tmpShield.Addr = row.Addr + ".shield"
				tmpShield.FieldName = row.Addr + ".屏蔽"
				tmpShield.Value = float64(row.Shield)
				extendList = append(extendList, &tmpShield)

			}
			err = tx.Create(&extendList).Error
			if err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    10,
			"message": err.Error(),
		})
		return
	}
	err = model.SyncFSEquipToMem(param.FSID)
	if err != nil {
		j_log.LogWarning([]interface{}{"SyncFSEquipToMem 同步内存数据失败", err})
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}
func (con FSController) ModuleDelete(ctx *gin.Context) {
	param := struct {
		ModuleID int `json:"module_id" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	info := model.FSModule{}
	err = model.DB.Where("id = ?", param.ModuleID).Limit(1).Find(&info).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	if info.ID == 0 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数 module_id",
			"data":    "",
		})
		return
	}
	_, ok := model.AllowModuleCode2[info.ModuleType]
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数 module_id~",
		})
		return
	}

	err = model.DB.Transaction(func(tx *gorm.DB) error {
		err = tx.Where("id = ?", param.ModuleID).Delete(&model.FSModule{}).Error
		if err != nil {
			return err
		}
		err = tx.Where("module_id = ?", param.ModuleID).Delete(&model.FrameItem{}).Error
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    10,
			"message": err.Error(),
		})
		return
	}

	err = model.SyncFSEquipToMem(info.FSID)
	if err != nil {
		j_log.LogWarning([]interface{}{"SyncFSEquipToMem 同步内存数据失败", err})
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}
func (con FSController) ModuleDeleteByType(ctx *gin.Context) {
	param := struct {
		ModuleType string `json:"module_type" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	list := make([]model.FSModule, 0)
	err = model.DB.Where("module_type = ?", param.ModuleType).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ids := make([]int, 0)
	for _, row := range list {
		ids = append(ids, row.ID)
	}
	if len(ids) == 0 {
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "success",
			"data": map[string]interface{}{
				"info": "当前类型下没有模块",
			},
		})
		return
	}

	err = model.DB.Transaction(func(tx *gorm.DB) error {
		err = tx.Where("id in ?", ids).Delete(&model.FSModule{}).Error
		if err != nil {
			return err
		}
		err = tx.Where("module_id in ?", ids).Delete(&model.FrameItem{}).Error
		if err != nil {
			return err
		}
		return nil
	})

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

// ChannelList 通道列表
func (con FSController) ChannelList(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		FSID       int    `json:"fs_id"`
		ModuleID   int    `json:"module_id"`
		FieldName  string `json:"field_name" binding:"max=30"`
		Addr       string `json:"addr" binding:"max=20"`
		SpecType   string `json:"spec_type" binding:"max=20"`
		SelectMode string `json:"select_mode"`
		model.QueryData
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	tx := model.DB.Model(&model.Channel{})
	tx.Where("project_id = ?", userToken.ProjectID)
	if param.FSID != 0 {
		tx.Where("fs_id = ?", param.FSID)
	}
	if param.ModuleID != 0 {
		tx.Where("module_id = ?", param.ModuleID)
	}
	if param.FieldName != "" {
		tx.Where("field_name like ?", "%"+param.FieldName+"%")
	}
	if param.Addr != "" {
		tx.Where("addr = ?", param.Addr)
	}
	if param.SpecType != "" {
		tx.Where("spec_type = ?", param.SpecType)
	}

	switch param.SelectMode {
	case "page_set": // 画面设置时设置变量
		tx.Where("module_id > 0")
	}

	var count int64
	list := make([]model.Channel, 0)
	err = tx.Count(&count).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	err = tx.Preload("ModuleInfo").Order("id ASC").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

// ModuleDownload 模块下载
func (con FSController) ModuleDownload(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		FSID         int    `json:"fs_id" binding:"required"`
		ModuleType   string `json:"module_type" binding:"required,max=20"`
		ModuleNumber int    `json:"module_number" binding:"required"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		_ = model.CommandHistoryLog(2, userToken.ProjectID, param.FSID, param.ModuleType+"模块下载", fmt.Sprintf("%s%02d下载", param.ModuleType, param.ModuleNumber), "admin/fs/module_download", param, 1, "FS设备TCP未连接")
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接 " + fse.Detail,
			"data":    map[string]interface{}{},
		})
		_ = model.CommandHistoryLog(2, userToken.ProjectID, param.FSID, param.ModuleType+"模块下载", fmt.Sprintf("%s%02d下载", param.ModuleType, param.ModuleNumber), "admin/fs/module_download", param, 1, "FS设备TCP未连接")
		return
	}

	data := make([]byte, 0)
	switch strings.ToUpper(param.ModuleType) {
	case "AI":
		data, err = model.GenFSModuleData0202(fse, fmt.Sprintf("%02d", param.ModuleNumber))
	case "AQ":
		data, err = model.GenFSModuleData0203(fse, fmt.Sprintf("%02d", param.ModuleNumber))
	case "DI":
		data, err = model.GenFSModuleData0204(fse, fmt.Sprintf("%02d", param.ModuleNumber))
	case "DQ":
		data, err = model.GenFSModuleData0205(fse, fmt.Sprintf("%02d", param.ModuleNumber))
	case "OTHER":
		data, err = model.GenFSModuleData0206(fse, fmt.Sprintf("%02d", param.ModuleNumber))
	default:
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    param.ModuleType,
		})
		return
	}
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": err.Error(),
		})
		return
	}

	_ = tools.WriteStringToLog(fmt.Sprintf("[%s~%s]【send】len=%d#%s", tools.GetNow(), fse.TcpClient.RemoteAddr, len(data), tools.ByteArrayToHexStr(data)), "module_download.log", "a")

	_, err = fse.Write(data)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "发送失败",
			"data":    err.Error(),
		})
		_ = model.CommandHistoryLog(2, userToken.ProjectID, param.FSID, param.ModuleType+"模块下载", fmt.Sprintf("%s%02d下载", param.ModuleType, param.ModuleNumber), "admin/fs/module_download", param, 1, "发送失败")
		return
	}

	tcpRequest := model.NewFSTCPRequest()
	key := time.Now().UnixNano()
	fse.TcpClient.Requests.Set(key, tcpRequest)
	defer fse.TcpClient.Requests.Delete(key)
	success := true
	hex := ""
	select {
	case hex = <-tcpRequest.Resp0202:
		success = true
	case hex = <-tcpRequest.Resp0282:
		success = false
	case hex = <-tcpRequest.Resp0203:
		success = true
	case hex = <-tcpRequest.Resp0283:
		success = false
	case hex = <-tcpRequest.Resp0204:
		success = true
	case hex = <-tcpRequest.Resp0284:
		success = false
	case hex = <-tcpRequest.Resp0205:
		success = true
	case hex = <-tcpRequest.Resp0285:
		success = false
	case hex = <-tcpRequest.Resp0206:
		success = true
	case hex = <-tcpRequest.Resp0286:
		success = false
	case <-time.After(3 * time.Second):
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "下载超时",
			"data": map[string]interface{}{
				"req": tools.ByteArrayToHexStr(data),
			},
		})
		_ = model.CommandHistoryLog(2, userToken.ProjectID, param.FSID, param.ModuleType+"模块下载", fmt.Sprintf("%s%02d下载", param.ModuleType, param.ModuleNumber), "admin/fs/module_download", param, 1, "下载超时")
		return
	}

	if success {
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "下载成功",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
		_ = model.CommandHistoryLog(2, userToken.ProjectID, param.FSID, param.ModuleType+"模块下载", fmt.Sprintf("%s%02d下载", param.ModuleType, param.ModuleNumber), "admin/fs/module_download", param, 0, "下载成功")

	} else {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "下载失败",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
		_ = model.CommandHistoryLog(2, userToken.ProjectID, param.FSID, param.ModuleType+"模块下载", fmt.Sprintf("%s%02d下载", param.ModuleType, param.ModuleNumber), "admin/fs/module_download", param, 1, "下载失败")
	}
}

// ModuleUpload 模块上载
func (con FSController) ModuleUpload(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		FSID         int    `json:"fs_id" binding:"required"`              // FS设备ID
		ModuleType   string `json:"module_type" binding:"required,max=20"` // 模块类型
		ModuleNumber uint8  `json:"module_number"`                         // 模块序号
		Debug        uint8  `json:"debug"`                                 // 如果为1则不执行FS基本信息读取校验
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	if param.ModuleNumber == 0 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "序号不可为0",
			"data":    "",
		})
		return
	}
	_, ok := model.AllowModuleCode2[param.ModuleType]
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数 module_type",
			"data": map[string]interface{}{
				"可选范围": model.AllowModuleCode2,
			},
		})
		return
	}
	code3 := fmt.Sprintf("%02d", param.ModuleNumber)
	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		_ = model.CommandHistoryLog(4, userToken.ProjectID, param.FSID, param.ModuleType+"模块上载", param.ModuleType+code3+"上载", "admin/fs/module_upload", param, 1, "FS设备TCP未连接")
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		_ = model.CommandHistoryLog(4, userToken.ProjectID, param.FSID, param.ModuleType+"模块上载", param.ModuleType+code3+"上载", "admin/fs/module_upload", param, 1, "FS设备TCP未连接")
		return
	}
	fseTmp, ok := model.TempFSMap.Get(param.FSID)
	if !ok {
		if param.Debug == 1 {
			fseTmp = &model.FSEquip{}
			fseTmp.DS = &model.DataScale{}
			fseTmp.DSModuleRead = 1
			model.TempFSMap.Set(param.FSID, fseTmp)
		} else {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "请先读取FS基本信息",
				"data":    map[string]interface{}{},
			})
			return
		}
	}
	if fseTmp.DSModuleRead == 0 {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "请先读取FS基本信息",
			"data":    map[string]interface{}{},
		})
		return
	}

	var moduleQuantity uint8
	data := []byte{0x5A, 0x04, 0x02, 0xCC, 0xCC, 0x01, 0x01}
	switch strings.ToUpper(param.ModuleType) {
	case "AI":
		moduleQuantity = fseTmp.DS.AI
		data[2] = 0x02
	case "AQ":
		moduleQuantity = fseTmp.DS.AQ
		data[2] = 0x03
	case "DI":
		moduleQuantity = fseTmp.DS.DI
		data[2] = 0x04
	case "DQ":
		moduleQuantity = fseTmp.DS.DQ
		data[2] = 0x05
	case "OTHER":
		moduleQuantity = fseTmp.DS.Other
		data[2] = 0x06
	default:
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    param.ModuleType,
		})
		return
	}
	if moduleQuantity == 0 {
		if param.Debug == 0 {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "模块数量为0",
				"data":    map[string]interface{}{},
			})
			return
		}
	}
	if param.ModuleNumber > moduleQuantity {
		if param.Debug == 0 {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "模块序号超出数据规模范围",
				"data": map[string]interface{}{
					"模块总数": moduleQuantity,
					"模块序号": param.ModuleNumber,
				},
			})
			return
		}
	}
	data = append(data, moduleQuantity, param.ModuleNumber, 0x00)
	data = append(data, 0x00, 0x00, 0x00, 0x00, 0xA5)
	model.FixDataLength(fse, data)
	_, err = fse.Write(data)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "发送失败",
			"data":    err.Error(),
		})
		_ = model.CommandHistoryLog(4, userToken.ProjectID, param.FSID, param.ModuleType+"模块上载", param.ModuleType+code3+"上载", "admin/fs/module_upload", param, 1, "发送失败")
		return
	}

	tcpRequest := model.NewFSTCPRequest()
	key := time.Now().UnixNano()
	fse.TcpClient.Requests.Set(key, tcpRequest)
	defer fse.TcpClient.Requests.Delete(key)
	success := true
	hex := ""
	select {
	case hex = <-tcpRequest.Resp0402:
		success = true
	case hex = <-tcpRequest.Resp0482:
		success = false
	case hex = <-tcpRequest.Resp0403:
		success = true
	case hex = <-tcpRequest.Resp0483:
		success = false
	case hex = <-tcpRequest.Resp0404:
		success = true
	case hex = <-tcpRequest.Resp0484:
		success = false
	case hex = <-tcpRequest.Resp0405:
		success = true
	case hex = <-tcpRequest.Resp0485:
		success = false
	case hex = <-tcpRequest.Resp0406:
		success = true
	case hex = <-tcpRequest.Resp0486:
		success = false
	case <-time.After(3 * time.Second):
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "上载超时",
			"data": map[string]interface{}{
				"req": tools.ByteArrayToHexStr(data),
			},
		})
		_ = model.CommandHistoryLog(4, userToken.ProjectID, param.FSID, param.ModuleType+"模块上载", param.ModuleType+code3+"上载", "admin/fs/module_upload", param, 1, "上载超时")
		return
	}

	if success {
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "上载成功",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
		_ = model.CommandHistoryLog(4, userToken.ProjectID, param.FSID, param.ModuleType+"模块上载", param.ModuleType+code3+"上载", "admin/fs/module_upload", param, 0, "上载成功")

	} else {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "上载失败",
			"data": map[string]interface{}{
				"req":  tools.ByteArrayToHexStr(data),
				"resp": hex,
			},
		})
		_ = model.CommandHistoryLog(4, userToken.ProjectID, param.FSID, param.ModuleType+"模型上载", param.ModuleType+code3+"上载", "admin/fs/module_upload", param, 1, "上载失败")
	}
}

func (con FSController) ModuleUploadApiList(ctx *gin.Context) {
	param := struct {
		FSID int `json:"fs_id" binding:"required"`
		//ModuleType string `json:"module_type"`
		//Apis       string `json:"apis" binding:"required"` // IP读取,IP设置,AI,AQ,DI,DQ,Other
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	fse, ok := model.RunningFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}
	if fse.RunningState != 2 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "FS设备TCP未连接",
			"data":    map[string]interface{}{},
		})
		return
	}

	tempFSE, ok := model.TempFSMap.Get(param.FSID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "请先读取FS基本信息~",
			"data":    map[string]interface{}{},
		})
		return
	}
	if tempFSE.DSModuleRead == 0 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "请先读取FS基本信息~half",
			"data":    map[string]interface{}{},
		})
		return
	}

	list := make([]*DownloadApi, 0)
	putFSModuleUploadAPI(tempFSE, &list, "AI", tempFSE.DS.AI)
	putFSModuleUploadAPI(tempFSE, &list, "AQ", tempFSE.DS.AQ)
	putFSModuleUploadAPI(tempFSE, &list, "DI", tempFSE.DS.DI)
	putFSModuleUploadAPI(tempFSE, &list, "DQ", tempFSE.DS.DQ)
	putFSModuleUploadAPI(tempFSE, &list, "Other", tempFSE.DS.Other)

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list": list,
		},
	})
}
